/**
 * 
 */
package vn.support.ui.frame;

import java.awt.TrayIcon;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.Timer;
import vn.support.connection.Connection;
import vn.support.connection.RequestConnection;
import vn.support.connection.factory.DataObjectFactory;
import vn.support.connection.factory.EntityFactory;
import vn.support.connection.response.processor.ResponseProcessor;
import vn.support.connection.response.processor.impl.StaffChatProcessor;
import vn.support.core.dto.DataObject;
import vn.support.core.dto.PendingChat;
import vn.support.core.dto.SessionData;
import vn.support.core.dto.Staff;
import vn.support.core.dto.Visitor;
import vn.support.system.SystemProperties;
import vn.support.ui.ContactView;

/**
 * @author nttuyen
 *
 */
public abstract class AbstractContactView extends JFrame implements ContactView {

    protected final SessionData session;
    protected final Connection connection;
    protected ResourceBundle bundle;

    protected final DataObject fetchVisitorData;
    protected final Timer fetchVisitorTimer;
    protected final EntityFactory factory;

    protected Collection<Staff> staffs;
    protected Collection<Visitor> visitors;
    protected Map<Long, Integer> staffStaus;
    protected Map<String, PendingChat> pendingChats;

    public AbstractContactView() {
        super.setIconImage(new ImageIcon(getClass().getResource(SystemProperties.getValue("support.chat.system.icon"))).getImage());

        this.session = SystemProperties.get(SystemProperties.SESSION);
        this.connection = new RequestConnection();
        this.bundle = ResourceBundle.getBundle(UI_BUNDLE);

        this.staffs = new ArrayList<Staff>();
        this.visitors = new ArrayList<Visitor>();
        this.staffStaus = new HashMap<Long, Integer>();
        this.pendingChats = new HashMap<String, PendingChat>();

        this.factory = new DataObjectFactory();
        this.fetchVisitorData = getFetchVisitorData();
        this.fetchVisitorTimer = getFetchVisitorTimer();
        this.fetchVisitorTimer.setInitialDelay(0);
        this.fetchVisitorTimer.start();
        SystemProperties.addView(this);
    }
    protected String bundle(String key) {
        if(this.bundle.containsKey(key)) {
            return this.bundle.getString(key);
        }
        return key;
    }

    protected final DataObject getFetchVisitorData() {
        DataObject data = new DataObject(Connection.FETCH_VISIITORS_ACTION);
        data.set("sessionid", session.getSessionId());
        data.set(Connection.RESPONSE_PROCESSOR, new ResponseProcessor() {
            @Override
            public DataObject process(final DataObject data) {
                String xml = data.get(Connection.DTO_RESPONSE_DATA);
                if(!xml.startsWith("<?xml")) {
                    if(fetchVisitorTimer.isRunning() && (Connection.RESPONSE_SESSION_TIMEOUT.equals(xml))) {
                        fetchVisitorTimer.stop();
                        int result = JOptionPane.showConfirmDialog(null, bundle("ui.dialog.notice.session.timeout.message.requirelogin"), bundle("ui.dialog.notice.session.timeout.title"), JOptionPane.OK_CANCEL_OPTION);
                        if(result == JOptionPane.OK_OPTION) {
                            LoginViewFrame login = new LoginViewFrame();
                            SystemProperties.set(SystemProperties.MAIN_FRAME, login);
                            login.setVisible(true);
                        }
                        dispose();
                        if(result != JOptionPane.OK_OPTION) {
                            System.exit(0);
                        }
                    }
                    return data;
                }
                visitors = factory.create(xml, "//swiftwinapp/visitor", Visitor.class);
                staffs = factory.create(xml, "//swiftwinapp/staff", Staff.class);
                Collection<PendingChat> pendingChats = factory.create(xml, "//swiftwinapp/pendingchat", PendingChat.class);
                for(PendingChat chat : pendingChats) {
                    if(chat.getVisitorSessionId() == null || chat.getVisitorSessionId().equals("")) {
                        DataObject aceptChat = new DataObject(Connection.ACCEPT_CHAT_ACTION);
                        aceptChat.set("sessionid", session.getSessionId());
                        aceptChat.set("chatsessionid", chat.getChatSessionId());
                        aceptChat.set("visitorsessionid", chat.getVisitorSessionId());
                        aceptChat.set(Connection.RESPONSE_PROCESSOR, new StaffChatProcessor());
                        Connection connection = new RequestConnection();
                        connection.execute(aceptChat);
                        pendingChats.remove(chat);
                    }
                }
                refreshStaff();
                refreshVisitor();
                refreshStaffStaus();
                refreshPendingChat(pendingChats);
                return data;
            }
        });
        return data;
    }

    @Override
    public void dispose() {
        SystemProperties.removeView(this);
        super.dispose();
    }

    protected void refreshPendingChat(Collection<PendingChat> pendingChats) {
        Map<String, PendingChat> chats = new HashMap<String, PendingChat>();
        for(PendingChat chat : pendingChats) {
            final PendingChat pending = chat;
            chats.put(chat.getChatSessionId(), chat);
            if(!this.pendingChats.containsKey(chat.getChatSessionId())) {
                this.showNotify(chat.getDisplayName(), chat.getDisplayName() + " " + bundle("ui.tray.notity.chat.pending.message"), TrayIcon.MessageType.INFO);
                final NotificationDialog dialog = new NotificationDialog(this, true);
                dialog.setMessage(chat.getDisplayName() + " " + bundle("ui.tray.notity.chat.pending.message"));
                dialog.addAcceptListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        dialog.dispose();
                        DataObject aceptChat = new DataObject(Connection.ACCEPT_CHAT_ACTION);
                        aceptChat.set("sessionid", session.getSessionId());
                        aceptChat.set("chatsessionid", pending.getChatSessionId());
                        aceptChat.set("visitorsessionid", pending.getVisitorSessionId());
                        aceptChat.set(Connection.RESPONSE_PROCESSOR, new StaffChatProcessor());
                        connection.execute(aceptChat);
                    }
                });
                dialog.addRefuseListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        dialog.dispose();
                        DataObject refuseChat = new DataObject(Connection.REFUSE_CHAT_ACTION);
                        refuseChat.set("sessionid", session.getSessionId());
                        refuseChat.set("chatsessionid", pending.getChatSessionId());
                        connection.execute(refuseChat);
                    }
                });
                dialog.setVisible(true);
                this.toFront();
            }
        }
        this.pendingChats = chats;
    }
    protected void refreshStaffStaus() {
        Map<Long, Integer> newStatus = new HashMap<Long, Integer>();
        for(Staff staff : this.staffs) {
            int status = staff.getStatus();
            newStatus.put(staff.getStaffId(), status);
            if(this.staffStaus.containsKey(staff.getStaffId())) {
                int oldStaus = this.staffStaus.get(staff.getStaffId());
                if(oldStaus != status) {
                    this.showNotify(staff.getStaffName(), staff.getStaffName() + " " + bundle("ui.tray.notify.staff.status." + status), TrayIcon.MessageType.INFO);
                }
            }
        }
        this.staffStaus = newStatus;
    }

    protected void showNotify(String title, String message, TrayIcon.MessageType type) {
        TrayIcon trayIcon = SystemProperties.get(SystemProperties.TRAY_ICON);
        if(trayIcon == null) return;
        trayIcon.displayMessage(title, message, type);
    }
    
    protected final Timer getFetchVisitorTimer() {
        Timer timer = new Timer(TIME_LOOP, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                fetchVisitorData.set("status", ((Integer)SystemProperties.get(SystemProperties.CURRENT_STATUS)).intValue());
                fetchVisitorData.set("randno", System.currentTimeMillis());
                connection.execute(fetchVisitorData);
            }
        });
        return timer;
    }
}
